package com.admin.system.security.jwt;

import com.admin.monmon.util.SecurityConstants;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author caixiaofeng
 * @version 1.0
 * @Description: <<>>
 * @company cxf
 * @create 2021-01-28 19:41
 */
@Data
@ConfigurationProperties(prefix = "jwt")
@Component
public class JwtTokenUtils {

    /**
     * 生成token令牌
     *
     * @param userDetails 用户
     * @return 令token牌
     */
    public String generateToken(UserDetails userDetails) {
        return generateToken(userDetails.getUsername());
    }

    /**
     * 刷新令牌
     *
     * @param token 原令牌
     * @return 新令牌
     */
    public String refreshToken(String token) {
        //token中获得用户名
        String username = this.getUsername(token);
        //重新生成新的token
        return this.generateToken(username);
    }

    /**
     * 验证令牌
     *
     * @param token       令牌
     * @param userDetails 用户
     * @return 是否有效
     */
    public Boolean validateToken(String token, UserDetails userDetails) {
        String username = this.getUsername(token);
        return (username.equals(userDetails.getUsername()));
    }

    /**
     * 验证令牌
     *
     * @param token 令牌
     * @return 是否有效
     */
    public Boolean validateToken(String token, String username) {
        String tokenUsername = this.getUsername(token);
        return (username.equals(tokenUsername));
    }

    /**
     * 从token令牌中获取用户名
     *
     * @param token
     * @return
     */
    public String getUsername(String token) {
        Jws<Claims> claimsJws = Jwts.parser()
                //传入密钥
                .setSigningKey(SecurityConstants.JWT_SECRET.getBytes())
                //传入token
                .parseClaimsJws(token.replace("Bearer ", ""));
        //获得用户名
        return claimsJws.getBody().getSubject();
    }

    /**
     * 生成token令牌
     *
     * @param username
     * @return
     */
    public String generateToken(String username) {
        //jwt失效时间
        Date expirationDate = new Date(System.currentTimeMillis() + SecurityConstants.TOKEN_EXPIRATION);
        //密钥
        SecretKey secretKey = Keys.hmacShaKeyFor(SecurityConstants.JWT_SECRET.getBytes());
        //构建Token
        return SecurityConstants.TOKEN_PREFIX + Jwts.builder()
                //设置jwt设置唯一编号
                //.setId("666")
                //jwt签发时间
                .setIssuedAt(new Date())
                //jwt失效时间
                .setExpiration(expirationDate)
                //设置toke头参数
                .setHeaderParam("type", SecurityConstants.TOKEN_TYPE)
                //设置密钥+加密签名
                .signWith(secretKey, SignatureAlgorithm.HS512)
                //设置token发行人
                .setIssuer(SecurityConstants.TOKEN_ISSUER)
                //设置token平台
                .setAudience(SecurityConstants.TOKEN_AUDIENCE)
                //设置jwt主题，可以是JSON数据
                .setSubject(username)
                //自定义信息，可以有多个---> 这里我用来放用户权限
                // .claim("auth", auth)
                //自定义信息，可以有多个
                //.setClaims(claims)
                .compact();
    }

    /**
     * 从token中获取用户权限
     *
     * @return
     */
    /*public Set<SimpleGrantedAuthority> getAuthorityFromToken(String token) {
        Jws<Claims> claimsJws = Jwts.parser()
                //传入密钥
                .setSigningKey(SecurityConstants.JWT_SECRET)
                //传入token
                .parseClaimsJws(token.replace("Bearer ", ""));

        //获得用户权限
        Set<?> auth = (Set<?>) claimsJws.getBody().get("username");
        return auth.stream().map(authority -> new SimpleGrantedAuthority((String) authority)).collect(Collectors.toSet());
    }*/
}
